/*
 * Copyright (C) 2014 Tolstykh Vladislav
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

package lib.search.engine;

import com.google.common.collect.TreeMultimap;
import java.util.TreeMap;

/**
 * Образец.
 * @author Толстых Владислав
 */
class Pattern {
    private final TreeMap<Integer, Character> TM;
    private boolean verified;
    private TreeMultimap<Integer, Character> needleMap;
    /**
     * Новый образец поиска.
     * @param tm хэш стиха
     */
    Pattern(TreeMap<Integer, Character> tm) {
        TM = tm;
        verified =false;
    }
    
    /**
     * Строка целиком (полное совпадение).
     * @param map хэш запроса
     */
    void wholeLine(TreeMultimap<Integer, Character> map) {
        int firstMatch = 0; 
        int lastMatch = 0; 
        int jumpLenght=1;
        needleMap=map;
        for (int step=1; step <= TM.size(); step+=jumpLenght) {
            int needleSize = needleMap.asMap().size();
            char ch = TM.get(step);
            //совпадение с первым символом образа
            if(ch==needleMap.get(1).first()){
                firstMatch = step;
                //номер последнего символа
                lastMatch = firstMatch + (needleSize-1);
                //останавливаем заблаговременно                        
                if(lastMatch > TM.size())
                    //образ поиска больше остатка символов в мэпе
                    break;      
                char segmentLastChar=TM.get(lastMatch);
                if(segmentLastChar!=needleMap.get(needleSize).first()){
                    jumpLenght=needleSize;
                    continue;
                }
            }
            //обрабатываем только первый и последний символ образа
            if(ch==needleMap.get(needleSize).first() & step==lastMatch){       
                //lastMatch инициализируется (если есть совпадение) раньше чем цикл дойдёт до очередного step
                int matchLenght=lastMatch-firstMatch;                                                
                //соответствие длины отрезка с длиной непроверенной части строки
                if(step+matchLenght > TM.size()){
                    //длина образа в данной точке больше длины текста
                    break;
                }else{
                    //совпадение длины отрезка (между первым и последним символом) с длиной образа
                    if((needleSize-1)==matchLenght){
                        verified=right2LeftCompare(firstMatch,needleSize);
                        firstMatch = 0;
                        lastMatch = 0;
                    }                            
                }                        
            }
            jumpLenght=1;
        }
    }
    
    /**
     * Искать частичные совпадения.
     * @param map хэш запроса
     */
    void overlap(TreeMultimap<Integer, Character> map) {
        //пока только идея
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }
    
    /**
     * Проверен.
     * @return cовпадения при поиске
     */
    boolean verified() {
        return verified;
    }
    
    /**
     * Сравнить справа налево.
     * @param firstMatch позиция первого совпадения по тексту
     * @param needleSize размер запроса
     * @return соответствие запроса образцу
     */
    private boolean right2LeftCompare (int firstMatch, int needleSize) {
        boolean bing = false;        
        //попытаемся ускорить поиск
        int turbo = 0;
        //идём по образу поиска, от предпоследного символа до второго (первый и последний итак совпадают)
        for (int backwards = needleSize-1; backwards > 0 ; backwards--) {
            //переменная встречается дважды по тексту, всё что могу о ней сказать
            int twice = backwards+1; 
            //символ из образа
            char chArrBack = needleMap.get(twice).first();
            //символ из мэпа
            char chTrmBack = TM.get(firstMatch+backwards);
            if(chArrBack==chTrmBack){
                if(turbo!=(twice) & turbo!=0){
                    //следующий символ (справа налево) отличается от образа
                    break;
                }else{
                    turbo=backwards; 
                }                
                if(backwards==1){
                    //найдено!
                    bing = true;                    
                }
            }else{
                break;
            }
        }
        return bing;
    }
    
}
